package com.looeyWei;

import com.util.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;

public class GamePanel extends JPanel implements ActionListener {

    public static final int SCREEN_WIDTH = 600;
    public static final int SCREEN_HEIGHT = 700;
    private static final int CELL_SIZE = 35;

    Tetromino currentOne = Tetromino.randomOne();

    Tetromino nextOne = Tetromino.randomOne();

    private Cell[][] wall = new Cell[18][9];

    /**
     * 游戏分数
     */
    int[] scoresPoll = {0, 1, 2, 5, 10};
    // 当前游戏分数
    private int totalScore = 0;
    //
    private int totalLine = 0;

    // status: playing,
    public static final int PLAYING = 0;
    public static final int PAUSE = 1;
    public static final int GAMEOVER = 2;
    public int currentStatus = 2;
    String[] showStatus = {"Space[暂停]", "Space[继续]", "S[重新开始]"};

    Timer timer;
    static final int DELAY = 500;

    GamePanel(){
        this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
//        this.setBackground(Color.BLACK);
        this.setFocusable(true);
        this.addKeyListener(new MyKeyAdapter());

        // 开始游戏
        startGame();
    }

    public void startGame(){
        currentStatus = PLAYING;
        timer = new Timer(DELAY, this);
        timer.start();
    }
    /**
     * 缓慢下落一格
     */
    public void downAction(){
        // 判断能否下落
        if(canDown()){
            currentOne.downMove();
        }else{
            // 将四方格嵌入墙中
            landToWall();
            // 判断是否能消行
            destoryLine();
            // 判断游戏是否结束
            if(isGameOver()){
                currentStatus = GAMEOVER;
            }else{
                currentOne = nextOne;
                nextOne = Tetromino.randomOne();
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        //
        g.translate(22, 15);

        paintwall(g);

        //
        paintCurrentOne(g);

        //
        paintNextOne(g);

        //
        paintScore(g);

        //
        paintStatus(g);
    }

    /**
     * 判断游戏是否结束
     */
    public boolean isGameOver(){
        Cell[] cells = nextOne.getCells();
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            if(wall[row][col] != null){
                return true;
            }
        }
        return false;
    }

    /**
     * 判断当前行是否满行
     * @return
     */
    public boolean isFullLine(int row){
        Cell[] cells = wall[row];
        for (Cell cell : cells) {
            if(cell == null){
                return false;
            }
        }
        return true;
    }

    /**
     * 消行
     */
    public void destoryLine(){
        // 统计当前消除的总行数
        int line = 0;
        Cell[] cells = currentOne.getCells();
        for (Cell cell : cells) {
            int row = cell.getRow();
            // 判断当前行是否满
            if(isFullLine(row)){
                line ++;
                // 消除操作
                for (int i = row; i > 0; i--) {
                    System.arraycopy(wall[i-1], 0, wall[i], 0, wall[0].length);
                }
                wall[0] = new Cell[9];
            }
        }
        // 统计分数
        totalScore += scoresPoll[line];
        totalLine += line;
    }

    /**
     * 判断方格是否能下落
     */
    public boolean canDown(){
        Cell[] cells = currentOne.getCells();
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            // 判断是否达到底部
            if(row == wall.length - 1){
                return false;
            }else if(wall[row + 1][col] != null){
                return false;
            }
        }
        return true;
    }

    /**
     * 瞬间下落
     */
    public void hardDownAction(){
        while(canDown()) {
            currentOne.downMove();
        }
        // 嵌入墙中
        landToWall();
        // 判断是否能消行
        destoryLine();
        // 判断游戏是否结束
        if(isGameOver()){
            currentStatus = GAMEOVER;
        }else{
            currentOne = nextOne;
            nextOne = Tetromino.randomOne();
        }
    }

    /**
     * 将四方格嵌入墙中
     */
    public void landToWall(){
        Cell[] cells = currentOne.getCells();
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            wall[row][col] = cell;
        }
    }

    /**
     * 瞬时间旋转
     */
    public void rotateRightAction(){
        currentOne.rotateRight();
        if(outOfBounds() || coincide()){
            currentOne.rotateLeft();
        }
    }

    /**
     * 游戏状态
     * @param g
     */
    private void paintStatus(Graphics g) {
        if(currentStatus == PLAYING){
            g.drawString(showStatus[0], 350, 600);
        }else if(currentStatus == PAUSE){
            g.drawString(showStatus[1], 350, 600);
        }else if(currentStatus == GAMEOVER){
            g.drawString(showStatus[2], 350, 600);
            g.setColor(Color.RED);
            g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));
            g.drawString("GAME OVER!", 30, 400);
        }
    }

    /**
     * 绘制分数
     * @param g
     */
    private void paintScore(Graphics g) {
        g.setFont(new Font(Font.DIALOG, Font.BOLD, 30));
        g.drawString("SCORE: " + totalScore, 350, 240);
        g.drawString("LINES: " + totalLine, 350,430);
    }

    /**
     * 下一个方块
     * @param g
     */
    private void paintNextOne(Graphics g) {
        Cell[] cells = nextOne.getCells();
        for (Cell cell : cells) {
            int x = cell.getCol() * CELL_SIZE + 250;
            int y = cell.getRow() * CELL_SIZE + 30;
            g.drawImage(cell.getImage(), x, y, CELL_SIZE, CELL_SIZE, null);
        }
    }

    /**
     * 描绘当前方块
     * @param g
     */
    private void paintCurrentOne(Graphics g) {
        Cell[] cells = currentOne.getCells();
        for (Cell cell : cells) {
            int x = cell.getCol() * CELL_SIZE;
            int y = cell.getRow() * CELL_SIZE;
            g.drawImage(cell.getImage(), x, y, CELL_SIZE, CELL_SIZE, null);
        }
    }

    /**
     * 绘制墙体
     * @param g
     */
    private void paintwall(Graphics g) {
        for (int i = 0; i < wall.length; i++) {
            for (int j = 0; j < wall[i].length; j++) {
                int x = j * CELL_SIZE;
                int y = i * CELL_SIZE;
                Cell cell = wall[i][j];
                if(cell == null){
                    g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
                }else{
                    g.drawImage(cell.getImage(), x, y, CELL_SIZE, CELL_SIZE,null);
                }
            }
        }
    }

    /**
     * 判断游戏是否出界
     * @return 出界了
     */
    public boolean outOfBounds(){
        Cell[] cells = currentOne.getCells();
        for (Cell cell : cells) {
            int col = cell.getCol();
            int row = cell.getRow();
            if(row < 0 || row > wall.length - 1 || col < 0 || col > wall[0].length - 1)
                return true;
        }
        return false;
    }

    /**
     * 判断方块是否重合
     * @return 是重合了
     */
    public boolean coincide(){
        Cell[] cells = currentOne.getCells();
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            if(wall[row][col] != null){
                return true;
            }
        }
        return false;
    }

    /**
     * 向左移动
     */
    public void moveLeftAction(){
        currentOne.leftMove();
        if(outOfBounds() || coincide()){
            currentOne.rightMove();
        }
    }
    /**
     * 向右移动
     */
    public void moveRightAction(){
        currentOne.rightMove();
        if(outOfBounds() || coincide()){
            currentOne.leftMove();
        }
    }

    /**
     * 资源加载
     */
    public static BufferedImage I;
    public static BufferedImage J;
    public static BufferedImage L;
    public static BufferedImage O;
    public static BufferedImage S;
    public static BufferedImage T;
    public static BufferedImage Z;

    static {
        InputStream resI = I.class.getResourceAsStream("/res/I.png");
        InputStream resJ = J.class.getResourceAsStream("/res/J.png");
        InputStream resL = L.class.getResourceAsStream("/res/L.png");
        InputStream resO = O.class.getResourceAsStream("/res/O.png");
        InputStream resS = S.class.getResourceAsStream("/res/S.png");
        InputStream resT = T.class.getResourceAsStream("/res/T.png");
        InputStream resZ = Z.class.getResourceAsStream("/res/Z.png");

        try {
            I = ImageIO.read(resI);
            J = ImageIO.read(resJ);
            L = ImageIO.read(resL);
            O = ImageIO.read(resO);
            S = ImageIO.read(resS);
            T = ImageIO.read(resT);
            Z = ImageIO.read(resZ);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (currentStatus == PLAYING) {
            // 缓慢下落一格
            downAction();
        }
        repaint();
    }

    public class MyKeyAdapter extends KeyAdapter{
        @Override
        public void keyPressed(KeyEvent e) {
            super.keyPressed(e);

            int code = e.getKeyCode();
            switch (code){
                case KeyEvent.VK_DOWN:
                    hardDownAction();
                    break;
                case KeyEvent.VK_LEFT:
                    moveLeftAction();
                    break;
                case KeyEvent.VK_RIGHT:
                    moveRightAction();
                    break;
                case KeyEvent.VK_UP:
                    rotateRightAction();  // 顺时针旋转
                    break;
                case KeyEvent.VK_SPACE:   // 瞬间下落
                    if(currentStatus == PLAYING)
                        currentStatus = PAUSE;
                    else if(currentStatus == PAUSE)
                        currentStatus = PLAYING;
                    break;
                case KeyEvent.VK_S:
                    currentStatus = PLAYING;
                    wall = new Cell[18][9];
                    currentOne = Tetromino.randomOne();
                    nextOne = Tetromino.randomOne();
                    totalLine = 0;
                    totalScore = 0;
                    break;
                default:
                    break;
            }
        }
    }
}
